#pragma once 
#include <bits/stdc++.h>
#include <shared_mutex>

/*****************************************************************************
 *! @brief 条件变量提供另外一种用于等待的同步机制, 他们阻塞一个或多个线程，知道收到另外的
 *!      线程发出的通知或者超时, 才会唤醒当前阻塞的线程.
 *
 *         
 *           
 * 
 *  
 ****************************************************************************/


//! 1. 使用condition_variable_any 与 mutex结合实现的同步队列
template<typename T>
class SyncQueue {
private:
	bool IsFull() const {
		return m_queue.size() == m_maxSize;
	}

	bool IsEmpty() const {
		return m_queue.empty();
	}

public:
	SyncQueue(int maxSize) : m_maxSize(maxSize) {
	}

	void put(const T& x) {
		// std::lock_guard<std::mutex> locker(m_mutex);

        //! v3
        std::unique_lock<std::mutex> locker(m_mutex);

        //! v1
        //! 可能会出现虚假唤醒，因为其获得锁后不会再次检查条件
		// while (IsFull()) {
		// 	std::cout << "缓冲区满了，需要等待..." << std::endl;
		// 	m_notFull.wait(m_mutex);              //! 进入休眠并释放锁, 等待被唤醒
		// }

        //! v2 
        //! 避免虚假唤醒:  获取锁后会再次检查条件，如果条件不满足则释放锁继续休眠等待
        m_notFull.wait(locker, [this](){ return !this->IsFull();});

     

		m_queue.push_back(x);
		m_notEmpty.notify_one();                   //! 告诉别人已经不为空
	}

	void pop(T& x) {
		// std::lock_guard<std::mutex> locker(m_mutex);

        //! v3
        std::unique_lock<std::mutex> locker(m_mutex);
		
        //! v1
		// while (IsEmpty()) {
		// 	std::cout << "缓冲区空了，需要等待..." << std::endl;
		// 	m_notEmpty.wait(m_mutex);             //! 进入休眠等待, 并释放锁
		// }
        //! v2
        m_notEmpty.wait(locker, [this](){ return !this->IsEmpty();});

		x = m_queue.front();
		m_queue.pop_front();
		m_notFull.notify_one();                   //! 告诉其他人已经不满了
	}

	bool empty() {
		std::lock_guard<std::mutex> locker(m_mutex);
		return m_queue.empty();
	}

	bool full() {
		std::lock_guard<std::mutex> locker(m_mutex);
		return m_queue.size() == m_maxSize;
	}

	size_t size() {
		std::lock_guard<std::mutex> locker(m_mutex);
		return m_queue.size();
	}

	int count() {
		return m_queue.size();
	}

private:
	std::list<T> m_queue;                       // 真实队列缓冲区
	std::mutex   m_mutex;                       // 互斥锁
	// std::condition_variable_any m_notEmpty;  // 不为空的条件
	// std::condition_variable_any m_notFull;   // 未满的条件

    //! v3
    std::condition_variable m_notEmpty;         // 不为空的条件
	std::condition_variable m_notFull;          // 未满的条件
	int m_maxSize;                              //ͬ 队列大小
};


//!  共享锁，C++17 开始支持
class SharedLocker {
public:
	void reader(int id) {
		std::shared_lock<std::shared_mutex> locker(m_mutex);
		//! 多个读者可以同时读取
		//! shared_lock 是只读锁
		std::cout << "reader" << id << std::endl;
	}
	
	//! 读写分离
	// 1. 如果一个线程获得读锁，则其他线程也可以获得
	// 2. 如果一个线程获得写锁，则其他线程不能获得
	void writer(int val) {
		std::unique_lock<std::shared_mutex> locker(m_mutex);
		m_data = val;
		std::cout << "writer" << m_data	<< std::endl;
    }
private:
    std::shared_mutex m_mutex;
	int               m_data;
};



int std_condition_variable ();